#include "glue.h"
#include "GlueTypes.h"
#include "PCM_sourceGlue.h"

#include "reaper_plugin/reaper_plugin_functions.h"

// GetSetMediaTrackInfo accessors:

// takes UD(MediaTrack *) returns UD(MediaTrack *)


// oh golly i hafta make them all like "GetMEDIATrackInfoParent"
// so I never hafta relookup what exactly these mess with!!!!!!

static int fGetMediaTrackInfoParent(lua_State *L)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *child = toMediaTrack(L, 1);
	MediaTrack *parent = (MediaTrack *) GetSetMediaTrackInfo(child, "P_PARTRACK", NULL);
	pushMediaTrack(L, parent);
	return 1;
}

// takes UD(MediaTrack *) returns string

static int fGetMediaTrackInfoName(lua_State *L)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	char *name = (char *) GetSetMediaTrackInfo(mtp, "P_NAME", NULL);
	lua_pushstring(L, name);
	return 1;
}

// takes (UD(MediaTrack *),string) returns void

static int fSetMediaTrackInfoName(lua_State *L)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	const char *name = luaL_checkstring(L, 2);
	void *answer = GetSetMediaTrackInfo(mtp, "P_NAME", (void *)name);

	return 0;
}

// takes UD(MediaTrack *) returns bool

static int fGetMediaTrackInfoBool(lua_State *L, const char *b_name)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	bool *answer = (bool *) GetSetMediaTrackInfo(mtp, b_name, NULL);
	lua_pushboolean(L, *answer);
	return 1;
}

// takes (UD(MediaTrack *), bool = true) returns void
static int fSetMediaTrackInfoBool(lua_State *L, const char *b_name)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	bool setting = true;	// because "Set" implies to actually Set it!

	MediaTrack *mtp = toMediaTrack(L, 1);

	int topidx = lua_gettop(L);

	if(topidx >= 2)
	{
		setting = luaL_checkboolean(L, 2);
	}

	void *answer = GetSetMediaTrackInfo(mtp, b_name, &setting);

	return 0;
}

#define mkgsMediaTrackInfoBool(FN,BN) \
	static int fGetMediaTrackInfo##FN(lua_State *L) { return fGetMediaTrackInfoBool(L, BN); }	\
	static int fSetMediaTrackInfo##FN(lua_State *L) { return fSetMediaTrackInfoBool(L, BN); }

mkgsMediaTrackInfoBool(Mute,"B_MUTE");
mkgsMediaTrackInfoBool(Phase, "B_PHASE");
mkgsMediaTrackInfoBool(ShowInMixer, "B_SHOWINMIXER");
mkgsMediaTrackInfoBool(MainSend, "B_MAINSEND");
mkgsMediaTrackInfoBool(FreeMode, "B_FREEMODE");

// takes UD(MediaTrack *) returns int

static int fGetMediaTrackInfoInt(lua_State *L, const char *i_name)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	int *answer = (int *) GetSetMediaTrackInfo(mtp, i_name, NULL);
	lua_pushinteger(L, *answer);
	return 1;
}

// takes (UD(MediaTrack *), int) returns void
static int fSetMediaTrackInfoInt(lua_State *L, const char *i_name)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	int	setting = luaL_checkinteger(L, 2);
	void *answer = GetSetMediaTrackInfo(mtp, i_name, &setting);

	return 0;
}

#define mkgsMediaTrackInfoInt(FN,IN) \
	static int fGetMediaTrackInfo##FN(lua_State *L) { return fGetMediaTrackInfoInt(L, IN); }	\
	static int fSetMediaTrackInfo##FN(lua_State *L) { return fSetMediaTrackInfoInt(L, IN); }

mkgsMediaTrackInfoInt(Solo, "I_SOLO");
mkgsMediaTrackInfoInt(FxEn, "I_FXEN");
mkgsMediaTrackInfoInt(RecArm, "I_RECARM");
mkgsMediaTrackInfoInt(RecInput, "I_RECINPUT");
mkgsMediaTrackInfoInt(RecMode, "I_RECMODE");
mkgsMediaTrackInfoInt(RecMon, "I_RECMON");
mkgsMediaTrackInfoInt(RecMonItems, "I_RECMONITEMS");
mkgsMediaTrackInfoInt(AutoMode, "I_AUTOMODE");
mkgsMediaTrackInfoInt(NChan, "I_NCHAN");
mkgsMediaTrackInfoInt(Selected, "I_SELECTED");
mkgsMediaTrackInfoInt(Wndh, "I_WNDH");
mkgsMediaTrackInfoInt(IsFolder, "I_ISFOLDER");
mkgsMediaTrackInfoInt(FolderCompact, "I_FOLDERCOMPACT");
mkgsMediaTrackInfoInt(MIDIHWOut, "I_MIDIHWOUT");
mkgsMediaTrackInfoInt(PerfFlags, "I_PERFFLAGS");
mkgsMediaTrackInfoInt(CustomColor, "I_CUSTOMCOLOR");
mkgsMediaTrackInfoInt(HeightOverride, "I_HEIGHTOVERRIDE");


// takes UD(MediaTrack *) returns double

static int fGetMediaTrackInfoDouble(lua_State *L, const char *d_name)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	double *answer = (double *) GetSetMediaTrackInfo(mtp, d_name, NULL);
	lua_pushnumber(L, *answer);
	return 1;
}

// takes (UD(MediaTrack *), double) returns void

static int fSetMediaTrackInfoDouble(lua_State *L, const char *d_name)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	double setting = luaL_checknumber(L, 2);
	void *answer = GetSetMediaTrackInfo(mtp, d_name, &setting);
	return 0;
}

#define mkgsMediaTrackInfoDouble(FN,DN) \
	static int fGetMediaTrackInfo##FN(lua_State *L) { return fGetMediaTrackInfoDouble(L, DN); }	\
	static int fSetMediaTrackInfo##FN(lua_State *L) { return fSetMediaTrackInfoDouble(L, DN); }

mkgsMediaTrackInfoDouble(Vol, "D_VOL");
mkgsMediaTrackInfoDouble(Pan, "D_PAN");
mkgsMediaTrackInfoDouble(PanLaw, "D_PANLAW");

// takes UD(MediaTrack *) returns float

static int fGetMediaTrackInfoFloat(lua_State *L, const char *f_name)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	float *answer = (float *) GetSetMediaTrackInfo(mtp, f_name, NULL);
	lua_pushnumber(L, *answer);
	return 1;
}

// takes (UD(MediaTrack *), float) returns void

static int fSetMediaTrackInfoFloat(lua_State *L, const char *f_name)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	float setting = (float) luaL_checknumber(L, 2);
	void *answer = GetSetMediaTrackInfo(mtp, f_name, &setting);

	return 0;
}

#define mkgsMediaTrackInfoFloat(FN,DN) \
	static int fGetMediaTrackInfo##FN(lua_State *L) { return fGetMediaTrackInfoFloat(L, DN); }	\
	static int fSetMediaTrackInfo##FN(lua_State *L) { return fSetMediaTrackInfoFloat(L, DN); }

mkgsMediaTrackInfoFloat(FxSend_Scale, "F_MCP_FXSEND_SCALE");
mkgsMediaTrackInfoFloat(SendRgn_Scale, "F_MCP_SENDRGN_SCALE");

// takes UD(MediaTrack *) returns number(interpretation of character)

static int fGetMediaTrackInfoBeatAttachMode(lua_State *L)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	char *answer = (char *) GetSetMediaTrackInfo(mtp, "C_BEATATTACHMODE", NULL);
	char a = answer[0];
	lua_pushnumber(L, a);
	return 1;
}

// takes (UD(MediaTrack *), number) returns void

static int fSetMediaTrackInfoBeatAttachMode(lua_State *L)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	char setting = (char) luaL_checknumber(L, 2);	// savage truncation!
	void *answer = GetSetMediaTrackInfo(mtp, "C_BEATATTACHMODE", &setting);
	return 0;
}

// takes UD(MediaTrack *) returns UD(GUID)
static int fGetMediaTrackInfoGuid(lua_State *L)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	GUID * gp = (GUID *) GetSetMediaTrackInfo(mtp, "GUID", NULL);
	GUID * gud = (GUID *) lua_newuserdata(L, sizeof(GUID));
	*gud = *gp;
	return 1;	// newuserdata pushed
}

// takes (UD(MediaTrack *), UD(GUID)) returns void

static int fSetMediaTrackInfoGuid(lua_State *L)
{
	assertFunctionPointer( GetSetMediaTrackInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	luaL_checktype(L, 2, LUA_TUSERDATA);
	GUID * gp = (GUID *) lua_touserdata(L, 2);
	void *answer = GetSetMediaTrackInfo(mtp, "GUID", gp);
	return 0;
}

//
// Now the Lua Registration Stuffination Doification

// this makes it explicit and I don't know if #Get##NM would work!
#define QUOTEME(x) #x

// makes two entries from name NM -> { "GetNM" , fGetNM }, { "SetNM" , fSetNM }

#define gsentry(NM) \
{	QUOTEME(Get##NM) , fGet##NM },	\
{	QUOTEME(Set##NM) , fSet##NM }

// makes two entries from name NM -> { "GetNM" , fMediaTrackInfoGetNM }, 
//									 { "SetNM" , fMediaTrackInfoSetNM }
// the table entry is a nice short name that maps to our
// humanly-readable-name-mangled funcs:

#define gsMediaTrackInfoEntry(NM) \
{	QUOTEME(Get##NM) , fGetMediaTrackInfo##NM }, \
{	QUOTEME(Set##NM) , fSetMediaTrackInfo##NM }

// perhaps a way to automate this via the mkers or something?
static const struct luaL_reg MediaTrackInfoReg [] =
{
	{"GetParent", fGetMediaTrackInfoParent},

	gsMediaTrackInfoEntry(Name),
	gsMediaTrackInfoEntry(Mute),
	gsMediaTrackInfoEntry(Phase),

	gsMediaTrackInfoEntry(ShowInMixer),
	gsMediaTrackInfoEntry(MainSend),
	gsMediaTrackInfoEntry(FreeMode),

	gsMediaTrackInfoEntry(Solo),
	gsMediaTrackInfoEntry(FxEn),
	gsMediaTrackInfoEntry(RecArm),
	gsMediaTrackInfoEntry(RecInput),
	gsMediaTrackInfoEntry(RecMode),
	gsMediaTrackInfoEntry(RecMon),
	gsMediaTrackInfoEntry(RecMonItems),
	gsMediaTrackInfoEntry(AutoMode),
	gsMediaTrackInfoEntry(NChan),

	gsMediaTrackInfoEntry(Selected),
	gsMediaTrackInfoEntry(Wndh),
	gsMediaTrackInfoEntry(IsFolder),
	gsMediaTrackInfoEntry(FolderCompact),
	gsMediaTrackInfoEntry(MIDIHWOut),
	gsMediaTrackInfoEntry(PerfFlags),
	gsMediaTrackInfoEntry(CustomColor),
	gsMediaTrackInfoEntry(HeightOverride),

	gsMediaTrackInfoEntry(Vol),
	gsMediaTrackInfoEntry(Pan),
	gsMediaTrackInfoEntry(PanLaw),

	gsMediaTrackInfoEntry(FxSend_Scale),
	gsMediaTrackInfoEntry(SendRgn_Scale),

	gsMediaTrackInfoEntry(BeatAttachMode),
	gsMediaTrackInfoEntry(Guid),

	{NULL, NULL}
};

// A table to hold all the GetSetMediaTrackInfo functions and constants

void MediaTrackInfoTable(lua_State *L)
{
	reaperTable(L, "MediaTrackInfo");	// parTable -> parTable chiTable  (top=right)

	luaL_register(L, NULL, MediaTrackInfoReg);	// register them in child table

	reaperStringConstant(L, "PARTRACK", "P_PARTRACK");
	reaperStringConstant(L, "NAME", "P_NAME");
	reaperStringConstant(L, "MUTE", "B_MUTE");
	reaperStringConstant(L, "PHASE", "B_PHASE");
	reaperStringConstant(L, "SOLO", "I_SOLO");
	reaperStringConstant(L, "FXEN", "I_FXEN");
	reaperStringConstant(L, "RECARM", "I_RECARM");
	reaperStringConstant(L, "RECINPUT", "I_RECINPUT");
	reaperStringConstant(L, "RECMODE", "I_RECMODE");
	reaperStringConstant(L, "RECMON", "I_RECMON");
	reaperStringConstant(L, "RECMONITEMS", "I_RECMONITEMS");
	reaperStringConstant(L, "AUTOMODE", "I_AUTOMODE");
	reaperStringConstant(L, "NCHAN", "I_NCHAN");
	reaperStringConstant(L, "SELECTED", "I_SELECTED");
	reaperStringConstant(L, "WNDH", "I_WNDH");
	reaperStringConstant(L, "ISFOLDER", "I_ISFOLDER");
	reaperStringConstant(L, "FOLDERCOMPACT", "I_FOLDERCOMPACT");
	reaperStringConstant(L, "MIDIHWOUT", "I_MIDIHWOUT");
	reaperStringConstant(L, "PERFFLAGS", "I_PERFFLAGS");
	reaperStringConstant(L, "CUSTOMCOLOR", "I_CUSTOMCOLOR");
	reaperStringConstant(L, "HEIGHTOVERRIDE", "I_HEIGHTOVERRIDE");
	reaperStringConstant(L, "VOL", "D_VOL");
	reaperStringConstant(L, "PAN", "D_PAN");
	reaperStringConstant(L, "PANLAW", "D_PANLAW");
	reaperStringConstant(L, "SHOWINMIXER", "B_SHOWINMIXER");
	reaperStringConstant(L, "MAINSEND", "B_MAINSEND");
	reaperStringConstant(L, "FREEMODE", "B_FREEMODE");
	reaperStringConstant(L, "BEATATTACHMODE", "C_BEATATTACHMODE");
	reaperStringConstant(L, "MCP_FXSEND_SCALE", "F_MCP_FXSEND_SCALE");
	reaperStringConstant(L, "MCP_SENDRGN_SCALE", "F_MCP_SENDRGN_SCALE");
	reaperStringConstant(L, "GUID", "GUID");

	lua_pop(L,1);

// Now the Main Reaper Table is on top of stack
// with our shiny  "MediaTrackInfo" table in it
}

//
// GetSetTrackSendInfo accessors:
//

static int fGetTrackSendInfoTrack(lua_State *L, const char *p_name)
{
	assertFunctionPointer( GetSetTrackSendInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	int category = luaL_checkinteger(L, 2);
	int sendidx = luaL_checkinteger(L, 3);
	MediaTrack *track = (MediaTrack *) GetSetTrackSendInfo(mtp, category, 
		sendidx, p_name, NULL);
	pushMediaTrack(L, track);
	return 1;
}

#define mkGetTrackSendInfoTrack(FN,DN) \
	static int fGetTrackSendInfo##FN(lua_State *L) { return fGetTrackSendInfoTrack(L, DN); }

mkGetTrackSendInfoTrack(DestTrack, "P_DESTTRACK");
mkGetTrackSendInfoTrack(SrcTrack, "P_SRCTRACK");

// takes mtp,cat,sidx
static int fGetTrackSendInfoBool(lua_State *L, const char *b_name)
{
	assertFunctionPointer( GetSetTrackSendInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	int category = luaL_checkinteger(L, 2);
	int sendidx = luaL_checkinteger(L, 3);
	bool *answer = (bool *) GetSetTrackSendInfo(mtp, category, 
		sendidx, b_name, NULL);
	if(answer)
	{
		lua_pushboolean(L, *answer);
		return 1;
	}
	return 0;
}

static int fSetTrackSendInfoBool(lua_State *L, const char *b_name)
{
	assertFunctionPointer( GetSetTrackSendInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	int category = luaL_checkinteger(L, 2);
	int sendidx = luaL_checkinteger(L, 3);

	bool setting = true;	// Set means to set by default
	if(lua_gettop(L) >= 4)
	{
		setting = luaL_checkboolean(L, 4);
	}

	void *answer = GetSetTrackSendInfo(mtp, category, 
		sendidx, b_name, &setting);

	return 0;
}

#define mkgsTrackSendInfoBool(FN,BN) \
	static int fGetTrackSendInfo##FN(lua_State *L) { return fGetTrackSendInfoBool(L, BN); }	\
	static int fSetTrackSendInfo##FN(lua_State *L) { return fSetTrackSendInfoBool(L, BN); }

mkgsTrackSendInfoBool(Mute, "B_MUTE");
mkgsTrackSendInfoBool(Phase, "B_PHASE");
mkgsTrackSendInfoBool(Mono, "B_MONO");

// takes mtp,cat,sendidx returns double

static int fGetTrackSendInfoDouble(lua_State *L, const char *d_name)
{
	assertFunctionPointer( GetSetTrackSendInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	int category = luaL_checkinteger(L, 2);
	int sendidx = luaL_checkinteger(L, 3);
	double *answer = (double *) GetSetTrackSendInfo(mtp, category, 
		sendidx, d_name, NULL);
	if(answer)
	{
		lua_pushnumber(L, *answer);
		return 1;
	}
	return 0;
}

// takes mtp,cat,sendidx, double returns void

static int fSetTrackSendInfoDouble(lua_State *L, const char *d_name)
{
	assertFunctionPointer( GetSetTrackSendInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	int category = luaL_checkinteger(L, 2);
	int sendidx = luaL_checkinteger(L, 3);

	double setting = luaL_checknumber(L, 4);
	void *answer = GetSetTrackSendInfo(mtp, category, 
		sendidx, d_name, &setting);

	return 0;
}

#define mkgsTrackSendInfoDouble(FN,DN) \
	static int fGetTrackSendInfo##FN(lua_State *L) { return fGetTrackSendInfoDouble(L, DN); }	\
	static int fSetTrackSendInfo##FN(lua_State *L) { return fSetTrackSendInfoDouble(L, DN); }

mkgsTrackSendInfoDouble(Vol, "D_VOL");
mkgsTrackSendInfoDouble(Pan, "D_PAN");
mkgsTrackSendInfoDouble(PanLaw, "D_PANLAW");

// takes mtp,cat,sendidx returns int

static int fGetTrackSendInfoInt(lua_State *L, const char *i_name)
{
	assertFunctionPointer( GetSetTrackSendInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	int category = luaL_checkinteger(L, 2);
	int sendidx = luaL_checkinteger(L, 3);
	int *answer = (int *) GetSetTrackSendInfo(mtp, category, 
		sendidx, i_name, NULL);
	if(answer)
	{
		lua_pushnumber(L, *answer);
		return 1;
	}
	return 0;
}

// takes mtp,cat,sendidx, double returns void

static int fSetTrackSendInfoInt(lua_State *L, const char *i_name)
{
	assertFunctionPointer( GetSetTrackSendInfo );

	MediaTrack *mtp = toMediaTrack(L, 1);
	int category = luaL_checkinteger(L, 2);
	int sendidx = luaL_checkinteger(L, 3);
	int setting = luaL_checkinteger(L, 4);

	void *answer = GetSetTrackSendInfo(mtp, category,
		sendidx, i_name, &setting);

	return 0;
}

#define mkgsTrackSendInfoInt(FN,DN) \
	static int fGetTrackSendInfo##FN(lua_State *L) { return fGetTrackSendInfoInt(L, DN); }	\
	static int fSetTrackSendInfo##FN(lua_State *L) { return fSetTrackSendInfoInt(L, DN); }

mkgsTrackSendInfoInt(SendMode, "I_SENDMODE");
mkgsTrackSendInfoInt(SrcChan, "I_SRCCHAN");
mkgsTrackSendInfoInt(DstChan, "I_DSTCHAN");
mkgsTrackSendInfoInt(MIDIFlags, "I_MIDIFLAGS");

// makes two entries from name NM -> { "GetNM" , fGetTrackSendInfoNM }, 
//									 { "SetNM" , fSetTrackSendInfoNM }
// the table entry is a nice short name that maps to our
// humanly-readable-name-mangled funcs:

#define gsTrackSendInfoEntry(NM) \
{	QUOTEME(Get##NM) , fGetTrackSendInfo##NM }, \
{	QUOTEME(Set##NM) , fSetTrackSendInfo##NM }

static const struct luaL_reg TrackSendInfoReg [] =
{
	{"GetDestTrack", fGetTrackSendInfoDestTrack},
	{"GetSrcTrack", fGetTrackSendInfoSrcTrack},

	gsTrackSendInfoEntry(Mute),
	gsTrackSendInfoEntry(Phase),
	gsTrackSendInfoEntry(Mono),

	gsTrackSendInfoEntry(Vol),
	gsTrackSendInfoEntry(Pan),
	gsTrackSendInfoEntry(PanLaw),

	gsTrackSendInfoEntry(SendMode),
	gsTrackSendInfoEntry(SrcChan),
	gsTrackSendInfoEntry(DstChan),
	gsTrackSendInfoEntry(MIDIFlags),

	{ NULL , NULL }
};

// A table to hold all the GetSetMediaTrackInfo functions and constants

void TrackSendInfoTable(lua_State *L)
{
	reaperTable(L, "TrackSendInfo");	// tableOLD -> tableOLD tableNEW  (top=right)

	luaL_register(L, NULL, TrackSendInfoReg);	// register it in OLD table

	reaperStringConstant(L, "DESTTRACK", "P_DESTTRACK");
	reaperStringConstant(L, "SRCTRACK", "P_SRCTRACK");

	reaperStringConstant(L, "MUTE", "B_MUTE");
	reaperStringConstant(L, "PHASE", "B_PHASE");
	reaperStringConstant(L, "MONO", "B_MONO");

	reaperStringConstant(L, "VOL", "D_VOL");
	reaperStringConstant(L, "PAN", "D_PAN");
	reaperStringConstant(L, "PANLAW", "D_PANLAW");

	reaperStringConstant(L, "SENDMODE", "I_SENDMODE");
	reaperStringConstant(L, "SRCCHAN", "I_SRCCHAN");
	reaperStringConstant(L, "DSTCHAN", "I_DSTCHAN");
	reaperStringConstant(L, "MIDIFLAGS", "I_MIDIFLAGS");

	lua_pop(L,1);

// Now the Main Reaper Table is on top of stack
// with our shiny  "TrackSendInfo" table in it
}

//
// GetSetMediaItemInfo accessors:
//
// void *(*GetSetMediaItemInfo)(MediaItem *item, const char *parmname, void *setNewValue);

// takes UD(MediaItem *) returns UD(MediaTrack *)

static int fGetMediaItemInfoParent(lua_State *L)
{
	assertFunctionPointer( GetSetMediaItemInfo );

	MediaItem *mip = toMediaItem(L, 1);
	MediaTrack *parent = (MediaTrack *) GetSetMediaItemInfo(mip, "P_TRACK", NULL);
	pushMediaTrack(L, parent);
	return 1;
}

// takes UD(MediaItem *) returns bool

static int fGetMediaItemInfoBool(lua_State *L, const char *b_name)
{
	assertFunctionPointer( GetSetMediaItemInfo );

	MediaItem *mip = toMediaItem(L, 1);
	bool *answer = (bool *) GetSetMediaItemInfo(mip, b_name, NULL);
	lua_pushboolean(L, *answer);
	return 1;
}

// takes (UD(MediaTrack *), bool = true) returns void

static int fSetMediaItemInfoBool(lua_State *L, const char *b_name)
{
	assertFunctionPointer( GetSetMediaItemInfo );

	bool setting = true;	// because "Set" implies to actually Set it!

	MediaItem *mip = toMediaItem(L, 1);

	int topidx = lua_gettop(L);

	if(topidx >= 2)
	{
		setting = luaL_checkboolean(L, 2);
	}

	void *answer = GetSetMediaItemInfo(mip, b_name, &setting);
	return 0;
}

#define mkgsMediaItemInfoBool(FN,BN) \
	static int fGetMediaItemInfo##FN(lua_State *L) { return fGetMediaItemInfoBool(L, BN); }	\
	static int fSetMediaItemInfo##FN(lua_State *L) { return fSetMediaItemInfoBool(L, BN); }

mkgsMediaItemInfoBool(Mute, "B_MUTE");
mkgsMediaItemInfoBool(LoopSrc, "B_LOOPSRC");
mkgsMediaItemInfoBool(AllTakesPlay, "B_ALLTAKESPLAY");
mkgsMediaItemInfoBool(UISel, "B_UISEL");

// takes UD(MediaMediaItem *) returns int

static int fGetMediaItemInfoInt(lua_State *L, const char *i_name)
{
	assertFunctionPointer( GetSetMediaItemInfo );

	MediaItem *mip = toMediaItem(L, 1);
	int *answer = (int *) GetSetMediaItemInfo(mip, i_name, NULL);
	lua_pushinteger(L, *answer);
	return 1;
}

// takes (UD(MediaTrack *), int) returns void

static int fSetMediaItemInfoInt(lua_State *L, const char *i_name)
{
	assertFunctionPointer( GetSetMediaItemInfo );

	MediaItem *mip = toMediaItem(L, 1);
	int	setting = luaL_checkinteger(L, 2);
	void *answer = GetSetMediaItemInfo(mip, i_name, &setting);
	return 0;
}

#define mkgsMediaItemInfoInt(FN,IN) \
	static int fGetMediaItemInfo##FN(lua_State *L) { return fGetMediaItemInfoInt(L, IN); }	\
	static int fSetMediaItemInfo##FN(lua_State *L) { return fSetMediaItemInfoInt(L, IN); }

mkgsMediaItemInfoInt(FadeInShape,"I_FADEINSHAPE");
mkgsMediaItemInfoInt(FadeOutShape,"I_FADEOUTSHAPE");
mkgsMediaItemInfoInt(GroupID,"I_GROUPID");
mkgsMediaItemInfoInt(LastY,"I_LASTY");
mkgsMediaItemInfoInt(LastH,"I_LASTH");
mkgsMediaItemInfoInt(CurTake,"I_CURTAKE");

// takes UD(MediaItem *) returns double

static int fGetMediaItemInfoDouble(lua_State *L, const char *d_name)
{
	assertFunctionPointer( GetSetMediaItemInfo );

	MediaItem *mip = toMediaItem(L, 1);
	double *answer = (double *) GetSetMediaItemInfo(mip, d_name, NULL);
	lua_pushnumber(L, *answer);
	return 1;
}

// takes (UD(MediaItem *), double) returns void

static int fSetMediaItemInfoDouble(lua_State *L, const char *d_name)
{
	assertFunctionPointer( GetSetMediaItemInfo );

	MediaItem *mip = toMediaItem(L, 1);
	double setting = luaL_checknumber(L, 2);
	void *answer = GetSetMediaItemInfo(mip, d_name, &setting);

	return 0;
}

#define mkgsMediaItemInfoDouble(FN,DN) \
	static int fGetMediaItemInfo##FN(lua_State *L) { return fGetMediaItemInfoDouble(L, DN); }	\
	static int fSetMediaItemInfo##FN(lua_State *L) { return fSetMediaItemInfoDouble(L, DN); }

mkgsMediaItemInfoDouble(Vol,"D_VOL");
mkgsMediaItemInfoDouble(Position,"D_POSITION");
mkgsMediaItemInfoDouble(Length,"D_LENGTH");
mkgsMediaItemInfoDouble(SnapOffset,"D_SNAPOFFSET");
mkgsMediaItemInfoDouble(FadeInLen,"D_FADEINLEN");
mkgsMediaItemInfoDouble(FadeOutLen,"D_FADEOUTLEN");
mkgsMediaItemInfoDouble(FadeInLen_Auto,"D_FADEINLEN_AUTO");
mkgsMediaItemInfoDouble(FadeOutLen_Auto,"D_FADEOUTLEN_AUTO");

// takes UD(MediaItem *) returns float
static int fGetMediaItemInfoFloat(lua_State *L, const char *f_name)
{
	assertFunctionPointer( GetSetMediaItemInfo );

	MediaItem *mip = toMediaItem(L, 1);
	float *answer = (float *) GetSetMediaItemInfo(mip, f_name, NULL);
	lua_pushnumber(L, *answer);
	return 1;
}

// takes (UD(MediaItem *), float) returns void

static int fSetMediaItemInfoFloat(lua_State *L, const char *f_name)
{
	assertFunctionPointer( GetSetMediaItemInfo );

	MediaItem *mip = toMediaItem(L, 1);
	float setting = (float) luaL_checknumber(L, 2);
	void *answer = GetSetMediaItemInfo(mip, f_name, &setting);
	return 0;
}

#define mkgsMediaItemInfoFloat(FN,DN) \
	static int fGetMediaItemInfo##FN(lua_State *L) { return fGetMediaItemInfoFloat(L, DN); }	\
	static int fSetMediaItemInfo##FN(lua_State *L) { return fSetMediaItemInfoFloat(L, DN); }

mkgsMediaItemInfoFloat(FreeMode_Y, "F_FREEMODE_Y");
mkgsMediaItemInfoFloat(FreeMode_H, "F_FREEMODE_H");

// takes UD(MediaItem *) returns number(interpretation of character)

static int fGetMediaItemInfoBeatAttachMode(lua_State *L)
{
	assertFunctionPointer( GetSetMediaItemInfo );

	MediaItem *mip = toMediaItem(L, 1);
	char *answer = (char *) GetSetMediaItemInfo(mip, "C_BEATATTACHMODE", NULL);
	char a = answer[0];
	lua_pushnumber(L, a);
	return 1;
}

// takes (UD(MediaItem *), number) returns void

static int fSetMediaItemInfoBeatAttachMode(lua_State *L)
{
	assertFunctionPointer( GetSetMediaItemInfo );

	MediaItem *mip = toMediaItem(L, 1);
	char setting = (char) luaL_checknumber(L, 2);	// savage truncation!
	void *answer = GetSetMediaItemInfo(mip, "C_BEATATTACHMODE", &setting);
	return 0;
}

#define gsMediaItemInfoEntry(NM) \
{	QUOTEME(Get##NM) , fGetMediaItemInfo##NM }, \
{	QUOTEME(Set##NM) , fSetMediaItemInfo##NM }

static const struct luaL_reg MediaItemInfoReg [] =
{
	{"GetParent",	fGetMediaItemInfoParent},
					
	gsMediaItemInfoEntry(Mute),
	gsMediaItemInfoEntry(LoopSrc),
	gsMediaItemInfoEntry(AllTakesPlay),
	gsMediaItemInfoEntry(UISel),

	gsMediaItemInfoEntry(FadeInShape),
	gsMediaItemInfoEntry(FadeOutShape),
	gsMediaItemInfoEntry(GroupID),
	gsMediaItemInfoEntry(LastY),
	gsMediaItemInfoEntry(LastH),
	gsMediaItemInfoEntry(CurTake),

	gsMediaItemInfoEntry(Vol),
	gsMediaItemInfoEntry(Position),
	gsMediaItemInfoEntry(Length),
	gsMediaItemInfoEntry(SnapOffset),
	gsMediaItemInfoEntry(FadeInLen),
	gsMediaItemInfoEntry(FadeOutLen),
	gsMediaItemInfoEntry(FadeInLen_Auto),
	gsMediaItemInfoEntry(FadeOutLen_Auto),

	gsMediaItemInfoEntry(FreeMode_Y),
	gsMediaItemInfoEntry(FreeMode_H),

	gsMediaItemInfoEntry(BeatAttachMode),


	{ NULL , NULL }
};

// A table to hold all the GetSetMediaItemInfo functions and constants

void MediaItemInfoTable(lua_State *L)
{
	reaperTable(L, "MediaItemInfo");	// tableOLD -> tableOLD tableNEW  (top=right)

	luaL_register(L, NULL, MediaItemInfoReg);	// register it in OLD table

	reaperStringConstant(L, "TRACK", "P_TRACK");

	reaperStringConstant(L, "MUTE", "B_MUTE");
	reaperStringConstant(L, "LOOPSRC", "B_LOOPSRC");
	reaperStringConstant(L, "ALLTAKESPLAY", "B_ALLTAKESPLAY");
	reaperStringConstant(L, "UISEL", "B_UISEL");

	reaperStringConstant(L, "BEATATTACHMODE", "C_BEATATTACHMODE");

	reaperStringConstant(L, "VOL", "D_VOL");
	reaperStringConstant(L, "POSITION", "D_POSITION");
	reaperStringConstant(L, "LENGTH", "D_LENGTH");
	reaperStringConstant(L, "SNAPOFFSET", "D_SNAPOFFSET");
	reaperStringConstant(L, "FADEINLEN", "D_FADEINLEN");
	reaperStringConstant(L, "FADEOUTLEN", "D_FADEOUTLEN");
	reaperStringConstant(L, "FADEINLEN_AUTO", "D_FADEINLEN_AUTO");
	reaperStringConstant(L, "FADEOUTLEN_AUTO", "D_FADEOUTLEN_AUTO");

	reaperStringConstant(L, "FADEINSHAPE", "I_FADEINSHAPE");
	reaperStringConstant(L, "FADEOUTSHAPE", "I_FADEOUTSHAPE");
	reaperStringConstant(L, "GROUPID", "I_GROUPID");
	reaperStringConstant(L, "LASTY", "I_LASTY");
	reaperStringConstant(L, "LASTH", "I_LASTH");
	reaperStringConstant(L, "CURTAKE", "I_CURTAKE");

	reaperStringConstant(L, "FREEMODE_Y", "F_FREEMODE_Y");
	reaperStringConstant(L, "FREEMODE_H", "F_FREEMODE_H");

	lua_pop(L,1);

// Now the Main Reaper Table is on top of stack
// with our shiny  "ItemInfo" table in it
}

// takes UD(MediaItem_Take *) returns UD(MediaTrack *)

static int fGetMediaItemTakeInfoTrack(lua_State *L)
{
	assertFunctionPointer( GetSetMediaItemTakeInfo );

	MediaItem_Take *take = toMediaItem_Take(L, 1);
	MediaTrack *mtp = (MediaTrack *) GetSetMediaItemTakeInfo(take, "P_TRACK", NULL);
	pushMediaTrack(L, mtp);
	return 1;
}

// takes UD(MediaItem_Take *) returns UD(MediaItem *)

static int fGetMediaItemTakeInfoItem(lua_State *L)
{
	assertFunctionPointer( GetSetMediaItemTakeInfo );

	MediaItem_Take *take = toMediaItem_Take(L, 1);
	MediaItem *mip = (MediaItem *) GetSetMediaItemTakeInfo(take, "P_ITEM", NULL);
	pushMediaItem(L, mip);
	return 1;
}

// takes UD(MediaItem_Take *) returns string

static int fGetMediaItemTakeInfoName(lua_State *L)
{
	assertFunctionPointer( GetSetMediaItemTakeInfo );
	MediaItem_Take *take = toMediaItem_Take(L, 1);
	char *name = (char *) GetSetMediaItemTakeInfo(take, "P_NAME", NULL);
	lua_pushstring(L, name);
	return 1;
}

// takes (UD(MediaItem_Take *), string) returns void

static int fSetMediaItemTakeInfoName(lua_State *L)
{
	assertFunctionPointer( GetSetMediaItemTakeInfo );

	MediaItem_Take *take = toMediaItem_Take(L, 1);
	const char *name = luaL_checkstring(L, 2);
	void *answer = GetSetMediaItemTakeInfo(take, "P_NAME", (void *)name);
	return 0;
}

// takes UD(MediaItem_Take *) returns bool

static int fGetMediaItemTakeInfoBool(lua_State *L, const char *b_name)
{
	assertFunctionPointer( GetSetMediaItemTakeInfo );

	MediaItem_Take *take = toMediaItem_Take(L, 1);
	bool *answer = (bool *) GetSetMediaItemTakeInfo(take, b_name, NULL);
	lua_pushboolean(L, *answer);
	return 1;
}

// takes (UD(MediaItem_Take *), bool = true) returns void

static int fSetMediaItemTakeInfoBool(lua_State *L, const char *b_name)
{
	assertFunctionPointer( GetSetMediaItemTakeInfo );

	bool setting = true;	// because "Set" implies to actually Set it!

	MediaItem_Take *take = toMediaItem_Take(L,  1);

	int topidx = lua_gettop(L);

	if(topidx >= 2)
	{
		setting = luaL_checkboolean(L, 2);
	}

	void *answer = GetSetMediaItemTakeInfo(take, b_name, &setting);
	return 0;
}

#define mkgsMediaItemTakeInfoBool(FN,BN) \
	static int fGetMediaItemTakeInfo##FN(lua_State *L) { return fGetMediaItemTakeInfoBool(L, BN); }	\
	static int fSetMediaItemTakeInfo##FN(lua_State *L) { return fSetMediaItemTakeInfoBool(L, BN); }

mkgsMediaItemTakeInfoBool(PPitch, "B_PPITCH");

// takes UD(MediaItem_Take *) returns int

static int fGetMediaItemTakeInfoInt(lua_State *L, const char *i_name)
{
	assertFunctionPointer( GetSetMediaItemTakeInfo );

	MediaItem_Take *take = toMediaItem_Take(L, 1);
	int *answer = (int *) GetSetMediaItemTakeInfo(take, i_name, NULL);
	lua_pushinteger(L, *answer);
	return 1;
}

// takes (UD(MediaItem_Take *), int) returns void

static int fSetMediaItemTakeInfoInt(lua_State *L, const char *i_name)
{
	assertFunctionPointer( GetSetMediaItemTakeInfo );

	MediaItem_Take *take = toMediaItem_Take(L, 1);
	int	setting = luaL_checkinteger(L, 2);
	void *answer = GetSetMediaItemTakeInfo(take, i_name, &setting);
	return 0;
}

#define mkgsMediaItemTakeInfoInt(FN,IN) \
	static int fGetMediaItemTakeInfo##FN(lua_State *L) { return fGetMediaItemTakeInfoInt(L, IN); }	\
	static int fSetMediaItemTakeInfo##FN(lua_State *L) { return fSetMediaItemTakeInfoInt(L, IN); }

mkgsMediaItemTakeInfoInt(ChanMode, "I_CHANMODE");
mkgsMediaItemTakeInfoInt(PitchMode, "I_PITCHMODE");

// takes UD(MediaItem_Take *) returns double
static int fGetMediaItemTakeInfoDouble(lua_State *L, const char *i_name)
{
	assertFunctionPointer( GetSetMediaItemTakeInfo );

	MediaItem_Take *take = toMediaItem_Take(L, 1);
	double *answer = (double *) GetSetMediaItemTakeInfo(take, i_name, NULL);
	lua_pushnumber(L, *answer);
	return 1;
}

// takes (UD(MediaItem_Take *), double) returns void

static int fSetMediaItemTakeInfoDouble(lua_State *L, const char *i_name)
{
	assertFunctionPointer( GetSetMediaItemTakeInfo );

	MediaItem_Take *take = toMediaItem_Take(L, 1);
	double	setting = luaL_checknumber(L, 2);

	void *answer = GetSetMediaItemTakeInfo(take, i_name, &setting);
	return 0;
}

#define mkgsMediaItemTakeInfoDouble(FN,IN) \
	static int fGetMediaItemTakeInfo##FN(lua_State *L) { return fGetMediaItemTakeInfoDouble(L, IN); }	\
	static int fSetMediaItemTakeInfo##FN(lua_State *L) { return fSetMediaItemTakeInfoDouble(L, IN); }

mkgsMediaItemTakeInfoDouble(StartOffs, "D_STARTOFFS");
mkgsMediaItemTakeInfoDouble(Vol, "D_VOL");
mkgsMediaItemTakeInfoDouble(Pan, "D_PAN");
mkgsMediaItemTakeInfoDouble(PanLaw, "D_PANLAW");
mkgsMediaItemTakeInfoDouble(PlayRate, "D_PLAYRATE");
mkgsMediaItemTakeInfoDouble(Pitch, "D_PITCH");

// void *(*GetSetMediaItemTakeInfo)(MediaItem_Take *tk, const char *parmname, void *setNewValue);
// "P_SOURCE" : PCM_source *. Note that if setting this, you should first retrieve the old source, set the new, THEN delete the old.

// takes UD(MediaItem_Take *) returns luna(PCM_Source)

static int fGetMediaItemTakeInfoSource(lua_State *L)
{
	assertFunctionPointer( GetSetMediaItemTakeInfo );

	MediaItem_Take *take = toMediaItem_Take(L, 1);
	PCM_source *srcp = (PCM_source *) GetSetMediaItemTakeInfo(take, "P_SOURCE", NULL);
	pushPCM_source(L, srcp);
	return 1;
}

// takes ( UD(MediaItem_Take *) , UD(PCM_Source *) ) returns UD(PCM_Source *)

static int fSetMediaItemTakeInfoSource(lua_State *L)
{
	assertFunctionPointer( GetSetMediaItemTakeInfo );

	MediaItem_Take *tkp = toMediaItem_Take(L, 1);

	PCM_source *newSrc = (PCM_source * ) toReaperObject(L, 2);

	PCM_source *oldSrc = (PCM_source *) GetSetMediaItemTakeInfo(tkp, "P_SOURCE", NULL);

	void *dummy = GetSetMediaItemTakeInfo(tkp, "P_SOURCE", (void *)newSrc);

	pushPCM_source(L, oldSrc);	// so that it can be deleted
	return 1;
}

#define gsMediaItemTakeInfoEntry(NM) \
{	QUOTEME(Get##NM) , fGetMediaItemTakeInfo##NM }, \
{	QUOTEME(Set##NM) , fSetMediaItemTakeInfo##NM }

static const struct luaL_reg MediaItemTakeInfoReg [] =
{
	{ "GetTrack", fGetMediaItemTakeInfoTrack },
	{ "GetItem", fGetMediaItemTakeInfoItem },

	gsMediaItemTakeInfoEntry(Name),
	gsMediaItemTakeInfoEntry(PPitch),

	gsMediaItemTakeInfoEntry(ChanMode),
	gsMediaItemTakeInfoEntry(PitchMode),

	gsMediaItemTakeInfoEntry(StartOffs),
	gsMediaItemTakeInfoEntry(Vol),
	gsMediaItemTakeInfoEntry(Pan),
	gsMediaItemTakeInfoEntry(PanLaw),
	gsMediaItemTakeInfoEntry(PlayRate),
	gsMediaItemTakeInfoEntry(Pitch),

	gsMediaItemTakeInfoEntry(Source),

	{ NULL , NULL }
};

// A table to hold our GetSetMediaItemTakeInfo

void MediaItemTakeInfoTable(lua_State *L)
{
	reaperTable(L, "MediaItemTakeInfo");	// tableOLD -> tableOLD tableNEW  (top=right)

	luaL_register(L, NULL, MediaItemTakeInfoReg);	// register it in OLD table

	reaperStringConstant(L, "TRACK", "P_TRACK");
	reaperStringConstant(L, "ITEM", "P_ITEM");
	reaperStringConstant(L, "NAME", "P_NAME");
	reaperStringConstant(L, "SOURCE", "P_SOURCE");

	reaperStringConstant(L, "STARTOFFS", "D_STARTOFFS");
	reaperStringConstant(L, "VOL", "D_VOL");
	reaperStringConstant(L, "PAN", "D_PAN");
	reaperStringConstant(L, "PANLAW", "D_PANLAW");
	reaperStringConstant(L, "PLAYRATE", "D_PLAYRATE");
	reaperStringConstant(L, "PITCH", "D_PITCH");

	reaperStringConstant(L, "PPITCH", "B_PPITCH");
	reaperStringConstant(L, "CHANMODE", "I_CHANMODE");
	reaperStringConstant(L, "PITCHMODE", "I_PITCHMODE");

	lua_pop(L,1);

// Now the Main Reaper Table is on top of stack
// with our shiny  "TakeInfo" table in it
}

void PCM_SourceTable(lua_State *L)
{
	reaperTable(L, "PCM_Source");	// {main} -> {main} {main.PCM_Source}

	reaperNumberConstant(L, "PCM_SOURCE_EXT_OPENEDITOR", 0x10001); // parm1=hwnd, parm2=track idx, parm3=item description
	reaperNumberConstant(L, "PCM_SOURCE_EXT_GETEDITORSTRING", 0x10002); // parm1=index (0 or 1), returns desc
// 0x10003 is deprecated
	reaperNumberConstant(L, "PCM_SOURCE_EXT_SETITEMCONTEXT", 0x10004); // parm1=pointer to item handle, parm2=pointer to take handle
	reaperNumberConstant(L, "PCM_SOURCE_EXT_ADDMIDIEVENTS", 0x10005); // parm1=pointer to midi_realtime_write_struct_t, nch=1 for replace, =0 for overdub, parm2=midi_quantize_mode_t* (optional)
	reaperNumberConstant(L, "PCM_SOURCE_EXT_GETASSOCIATED_RPP", 0x10006); // parm1=pointer to char* that will receive a pointer to the string
	reaperNumberConstant(L, "PCM_SOURCE_EXT_GETMETADATA", 0x10007);// parm1=pointer to name string, parm2=pointer to buffer, parm3=(int)buffersizemax . returns length used. Defined strings are "DESC", "ORIG", "ORIGREF", "DATE", "TIME", "UMID", "CODINGHISTORY" (i.e. BWF)
	reaperNumberConstant(L, "PCM_SOURCE_EXT_CONFIGISFILENAME", 0x20000);
	reaperNumberConstant(L, "PCM_SOURCE_EXT_GETBPMANDINFO", 0x40000); // parm1=pointer to double for bpm. parm2=pointer to double for snap/downbeat offset (seconds).
	reaperNumberConstant(L, "PCM_SOURCE_EXT_GETNTRACKS", 0x80000); // for midi data, returns number of tracks that would have been available
	reaperNumberConstant(L, "PCM_SOURCE_EXT_GETTITLE", 0x80001);
	reaperNumberConstant(L, "PCM_SOURCE_EXT_GETTEMPOMAP", 0x80002);
	reaperNumberConstant(L, "PCM_SOURCE_EXT_WANTOLDBEATSTYLE", 0x80003);
	reaperNumberConstant(L, "PCM_SOURCE_EXT_WANTTRIM", 0x90002); // bla
	reaperNumberConstant(L, "PCM_SOURCE_EXT_TRIMITEM", 0x90003); // parm1=lrflag, parm2=double *{position,length,startoffs,rate}


	lua_pop(L,1);					// {main}	// same as entry
}

void PCM_SinkTable(lua_State *L)
{
	reaperTable(L, "PCM_Sink");	// {main} -> {main} {main.PCM_Sink}

	reaperNumberConstant(L, "PCM_SOURCE_EXT_OPENEDITOR", 0x10001); // parm1=hwnd, parm2=track idx, parm3=item description

	reaperNumberConstant(L, "PCM_SINK_EXT_CREATESOURCE",  0x80000); // parm1 = PCM_source ** (will be created if supported)
	reaperNumberConstant(L, "PCM_SINK_EXT_DONE",  0x80001); // parm1 = HWND of the render dialog
	reaperNumberConstant(L, "PCM_SINK_EXT_VERIFYFMT",  0x80002); // parm1=int *srate, parm2= int *nch. plugin can override (and return 1!!)
	reaperNumberConstant(L, "PCM_SINK_EXT_SETQUANT",  0x80003); // parm1 = (midi_quantize_mode_t*), or NULL to disable
	reaperNumberConstant(L, "PCM_SINK_EXT_SETRATE",  0x80004); // parm1 = (double *) rateadj

	lua_pop(L,1);					// {main}	// same as entry
}

void ReaLuaTable(lua_State *L)
{
	reaperTable(L, "realua");	// {main} -> {main} {main.realua}

	char *pinit;
	size_t sinit;

	errno_t dserr = _dupenv_s(&pinit, &sinit, "REALUA_INIT");
	reaperStringConstant(L, "REALUA_INIT", pinit);	// pinit=NULL results in r.r.R_I=nil so it is okay

	reaperStringConstant(L, "version", REALUA_VERSION);
	reaperStringConstant(L, "built", __DATE__ " " __TIME__);
	reaperStringConstant(L, "page", "http://code.google.com/p/realua/");
	reaperStringConstant(L, "email", "reaper.lua@gmail.com");
	reaperStringConstant(L, "checkout", "svn checkout http://realua.googlecode.com/svn/trunk/ realua");

	reaperStringConstant(L, "copyright", "Copyright (C) 2009 Todd Hartmann, released under The MIT License");

	lua_pop(L,1);					// {main}	// same as entry
}

void HookTable(lua_State *L)
{
	reaperTable(L, "hooks");	// {main} -> {main} {main.hooks}
	lua_pop(L,1);				// {main}		// same as entry
}

void reaperSubTables(lua_State *L)
{
	MediaTrackInfoTable(L);
	TrackSendInfoTable(L);
	MediaItemInfoTable(L);
	MediaItemTakeInfoTable(L);
	PCM_SourceTable(L);
	PCM_SinkTable(L);

	ReaLuaTable(L);
	HookTable(L);
}
